<?php

namespace teamug;

/**
 * A data structure
 * Expects to be extended
 * Can be extended as a business object, or related to some resource. Eg MySQL
 * 
 */
class Model {
  
  // Override this in the extending class with default property values
  protected $properties = array();

  
  /**
   * Instantiate
   * 
   * @param array $data Assoc array to copy into the class's properties. Ignores keys if the property does not exist
   */
  
  public function __construct($data=null) {
    if (!\is_null($data)) {
      $this->populate($data);
    }
  }
 
  
  /**
   * Returns $this->$name
   * else returns $this->get_$name() if the method exists, and caches as a property
   * else triggers an error and returns null
   * Extending class may override this function
   * 
   * @param string $name Property name
   * @return mixed Property value / null and trigger a warning if property does not exist
   */
  public function __get($name) {
      
    if (\array_key_exists($this->properties, $name)) {
      return $this->properties[$name];
    } elseif (\method_exists($this, "get_$name")) {
      $method = "get_$name";
      $this->properties[$name] = $this->$method();
      return $this->properties[$name];
    } else {
      trigger_error(\get_class($this)." can not __get(). It has no property: '$name' or method: 'get_$name()'", E_USER_WARNING);
      return null;
    }
  }


  /**
   * Sets $this->$name
   * else calls $this->set_$name($value) if the function exists
   * else triggers an error
   * Extending class may override this function
   * 
   * @param string $name Property name
   * @param mixed $value Property value
   */
  public function __set($name, $value) {
      
    if (\array_key_exists($this->properties, $name)) {
      $this->properties[$name] = $value;
    } elseif (\method_exists($this, "set_$name")) {
      $method = "set_$name";
      $this->$method($value);
    } else {
      trigger_error(\get_class($this)." can not set. It has no property: '$name', or method: 'set_$name()", E_USER_WARNING);
    }
  }

   
  
  /**
   * Copy data from an assoc array to the object's properties
   * If the key does not match a property name, or set_xx() function then ignore it
   * 
   * @param array $data Assoc array of data to copy across
   */
  public function populate($data) {
    
    foreach($data AS $key => $value) {
      if (\array_key_exists($this->properties, $key)) {
        $this->properties[$key] = $value;
      } elseif (\method_exists($this, "set_$key")) {
        $method = "set_$name";
        $this->properties[$key] = $this->$method($value);
      }
    }
 
  }
  
 }
